/**
  ******************************************************************************
  * @file    w32f006_i2c.c
  * @author  WeiLink Technology
  * @version V1.0.0
  * @date    09/01/2020
  * @brief   This file provides firmware functions to manage the following 
  *          functionalities of the Inter-integrated circuit (I2C)
  *           - Initialization and Configuration
  *           - Data transfers
  *           - Interrupts, events and flags management        
  *  
  ******************************************************************************
  * @attention
  *
  * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
  * TIME. AS A RESULT, WeiLink Technology SHALL NOT BE HELD LIABLE FOR ANY
  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
  * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
  *
  * <h2><center>&copy; COPYRIGHT WeiLink Technology</center></h2>
  ******************************************************************************  
  */ 

/* Includes ------------------------------------------------------------------*/
#include "w32f006_i2c.h"
#include "w32f006_rcc.h"

/** @addtogroup W32F006_StdPeriph_Driver
  * @{
  */

/** @defgroup I2C 
  * @brief I2C driver modules
  * @{
  */ 

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define I2C_XBIT_SLAVE_SHIFT        3
#define I2C_XBIT_MASTER_SHIFT       4
#define I2C_DATA_CMD_CMD_READ       ((uint32_t)0x00000100)
#define I2C_DATA_CMD_CMD_WRITE      ((uint32_t)0x00000000)

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/** @defgroup I2C_Private_Functions
  * @{
  */

/**
  * @brief  Deinitialize the I2C peripheral registers to their default reset values.
  * @retval None
  */
void I2C_DeInit(void)
{
    RCC_APBPeriphResetCmd(RCC_PRESETCTRL_I2C0, ENABLE);
    RCC_APBPeriphResetCmd(RCC_PRESETCTRL_I2C0, DISABLE);
}

/**
  * @brief  Initializes the I2C peripheral according to the specified 
  *         parameters in the I2C_InitStruct.
  * @param  I2C_InitStruct: pointer to a I2C_InitTypeDef structure that contains 
  *         the configuration information for the specified I2C peripheral.
  * @retval None.
  */
void I2C_Init(I2C_InitTypeDef* I2C_InitStruct)
{
    uint32_t m, n;
    
    /* Check the parameters */
    assert_param(IS_I2C_Speed(I2C_InitStruct->I2C_ClockSpeed));
    
    n = RCC_GetClocksFreq(RCC_CLOCKFREQ_SYSAHBCLK) / 12000000;
    switch(n)
    {
        case 1:
            n = 0;
        break;
        case 2:
            n = 1;
        break;
        case 3:
            n = 2;
        break;
        case 4:
            n = 2;
        break;
        case 5:
            n = 3;
        break;
        case 6:
            n = 3;
        break;
        case 7:
            n = 3;
        break;
        case 8:
            n = 3;
        break;
        default:
            n = 3;
        break;
    }
        
    if (I2C_InitStruct->I2C_ClockSpeed == 100000)
    {
        m = 11;
    }
    else
    {
        m = 2;
    }
    
    I2C0->REG03.CCR = (m<<3) | n;
}

/**
  * @brief  Controls whether the DW_apb_i2c is enabled.
  * @param  NewState: new state of the I2C peripheral. 
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None.
  */
void I2C_Cmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        I2C0->CNTR |= I2C_CNTR_ENAB;
    }
    else
    {
        I2C0->CNTR &= ~I2C_CNTR_ENAB;
    }
}

/**
  * @brief  Sends a data byte through the I2C peripheral.
  * @param  Data: Byte to be transmitted..
  * @retval None
  */
void I2C_SendData(uint8_t Data)
{
    /* Write in the DR register the data to be sent */
    I2C0->DATA = Data;
}

/**
  * @brief  Returns the most recent received data by the I2C peripheral.
  * @retval The value of the received data.
  */
uint8_t I2C_ReceiveData(void)
{
    /* Return the data in the IC_DATA_CMD register */
    return (uint8_t)(I2C0->DATA);
}

/**
  * @brief  Send ACK.
  * @param  NewState: new state of the ACK command. 
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None.
  */
void I2C_ACKCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        I2C0->CNTR |= I2C_CNTR_AAK;
    }
    else
    {
        I2C0->CNTR &= ~I2C_CNTR_AAK;
    }
}

/**
  * @brief  Send Start.
  * @retval None.
  */
void I2C_StartCmd(void)
{
    I2C0->CNTR |= I2C_CNTR_STA;
}

/**
  * @brief  Send Stop.
  * @retval None.
  */
void I2C_StopCmd(void)
{
    I2C0->CNTR |= I2C_CNTR_STP;
}

/**
  * @brief  ACK General Call.
  * @param  NewState: When set to ENABLE, I2C responds with a ACK when it receives a General Call.
  *                   When set to DISABLE, I2C does not generate General Call interrupts.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None.
  */
void I2C_ACKGenCallCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        I2C0->ADDR |= I2C_ADDR_GCE;
    }
    else
    {
        I2C0->ADDR &= ~I2C_ADDR_GCE;
    }
}

/**
  * @brief  Set I2C Slave addr.
  * @param  Addr: I2C Slave address.
  * @param  Bits: This parameter can be: I2C_SLAVE_ADDR_7BITS or I2C_SLAVE_ADDR_10BITS.
  * @retval None.
  */
void I2C_SetSlaveAddr(uint32_t Addr, uint32_t Bits)
{
    /* Check the parameters */
    assert_param(IS_I2C_SLAVE_ADDR(Addr));
    assert_param(IS_I2C_SLAVE_ADDR_BITS(Bits));
    
    if (Bits == 7)
    {
        I2C0->ADDR = ((Addr & 0x7F) << 1) & 0xFF;
        I2C0->XADDR = 0;
    }
    else if (Bits == 10)
    {
        I2C0->XADDR = Addr & 0xFF;
        I2C0->ADDR = ((Addr >> 8) << 1) | (0x1E << 3);
    }
}

/**
  * @brief  Enables or disables the specified I2C interrupts.
  * @param  NewState: new state of the specified I2C interrupts.
  *          This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void I2C_ITCmd(FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected I2C interrupts */
        I2C0->CNTR |= I2C_CNTR_IEN;
    }
    else
    {
        /* Disable the selected I2C interrupts */
        I2C0->CNTR &= ~I2C_CNTR_IEN;
    }
}

/**
  * @brief  Get the I2C's Interrupt Status Register.
  * @retval The new state of the I2C_IT(SET or RESET).
  */
uint8_t I2C_GetITStatus(void)
{
    return (I2C0->REG03.STAT);
}

/**
  * @brief  Clears the I2C's interrupt pending bits.
  * @retval None
  */
void I2C_ClearITPendingBit(void)
{    
    I2C0->CNTR &= ~I2C_CNTR_IFLG;
}

/**
  * @brief  Clears the I2C's BusError pending bits.
  * @retval None
  */
void I2C_ClearBusError(void)
{
    uint8_t tmpreg;
    
    tmpreg = I2C0->CNTR;
    tmpreg &= ~I2C_CNTR_IFLG;
    tmpreg |= I2C_CNTR_STP;
    
    I2C0->CNTR = tmpreg;
}

/**
  * @}
  */ 

/**
  * @}
  */ 

/**
  * @}
  */ 

/******************* (C) COPYRIGHT WeiLink Technology *****END OF FILE****/
